import pygame, sys, json

# components
from components.air import Air
from components.alintFactory import AlintFactory 
from components.eventCenter import EventCenter
from components.bullet import BulletFactory
from components.airFactory import AirFactory
from components.button import Button
from components.scoreBar import ScoreBar, InfoBarConfig


class Game_cfg:
    
    def __init__(self):
        self.screen_w = 800
        self.screen_h = 600
        self.screen_top = 0
        self.screen_left = 32
        self.bg_img = 'static/bg.jpg'
        self.airNum = 2
        self.total = 0
    

class Game(EventCenter):
    
    def __init__(self, config):
        pygame.display.set_caption("Python Game")
        
        self.__config = config
        self.screne = {}
        self.bindEvent()

        self.screen = pygame.display.set_mode((config.screen_w, config.screen_h), 0, 32)
        self.bulletFactory = BulletFactory(self.screen)
        self.alienFactory = AlintFactory(self.screen, {"x": 10 ,"y": 400})
        self.airFactory = AirFactory(self.screen)
        self.action = False
        self.button = Button(self.screen,'play')

        self.buildScoreBar()
        self.button.bindMouseEvent(self.runGame)

    def buildBg(self):
        bg = pygame.image.load(self.__config.bg_img)
        self.screen.blit(bg, (0,0))
        
    
    def run(self):
        ''' 运行game '''
        
        while True:
            
            self.buildBg()
            self.triggerEvent()
            self.gameBlit()
    
            # 暂停
            if self.action:
                self.gameUpdate()
                self.collision()
            else:
                self.button.drawButton()
            
            pygame.display.flip()
            


    def collision(self):
        ''' 对象碰撞 '''
         
        bullets = self.bulletFactory.bullets
        alints = self.alienFactory.alints
        airs = self.airFactory.airs
        
        invalidAlint =  pygame.sprite.groupcollide(bullets, alints, True, True)

        # 击中敌人
        if invalidAlint:
            self.__config.total += 10
            self.trigger('removeAlint', {})

        # 飞机碰撞
        if airs:
            
            for item in airs:
                isDown = pygame.sprite.spritecollideany(item, alints)

                if isDown:
                    
                    self.__config.airNum -= 1
                    self.trigger('removeAir', item)
                    
                    if self.__config.airNum > 0:
                        self.trigger('createAir', self.screen)
                    else:
                        self.trigger('stopGame', {})
                        
        
    def bindEvent (self):
        ''' 绑定事件 '''
        
        def outGame(event):
            sys.exit()  

        def gameStatusTarget(event):
            if event.key == pygame.K_o:    
                self.gameStatus(not self.action)

        
        EventMap = {
            pygame.QUIT: outGame,
            pygame.KEYDOWN: gameStatusTarget,
            "stopGame": lambda e: self.stopGame(),
            "actionGame": lambda e: self.runGame()
        }


        for key, val in EventMap.items():    
            self.registered(key, val)

    def gameStatus(self, status=True):
        self.action = status
    
    def stopGame(self):
        self.action = False

    def runGame(self):
        self.action = True

    def gameBlit(self):
        self.trigger('gameBlit', {})
        
    def gameUpdate(self):
        self.trigger('gameUpdate', {})

    def triggerEvent(self):
        ''' 触发事件 '''
        
        for event in pygame.event.get():
            self.trigger(event.type, event)

    def buildScoreBar(self):
        self.scoreBar = ScoreBar(self.screen)

        def updateAriInfo(infoBar, event):
            ariNum = self.__config.airNum
            print('run', ariNum)
            msg = 'air: %d' % (ariNum)
            infoBar.updateMeg(msg)
        
        def updateTotalInfo(infoBar, event):
            total = self.__config.total
            msg = 'total: %d' % (self.__config.total)
            infoBar.updateMeg(msg)
        

        
        ariConfig = [

            InfoBarConfig('air: %d' % (self.__config.airNum), 80, 50),
            "removeAir",
            updateAriInfo
        ]
        
        totalConfig = [

            InfoBarConfig('total: %d' % (self.__config.total), 80, 20),
            "removeAlint",
            updateTotalInfo
        ]

        self.scoreBar.add(*ariConfig)
        self.scoreBar.add(*totalConfig)
        


config = Game_cfg()
game = Game(config)
game.run()